package igloo.model;

import igloo.aws.Region;
import igloo.util.DateUtil;
import igloo.util.EventSupport;
import igloo.util.IEventRaiser;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodb.model.AttributeValue;
import com.amazonaws.services.glacier.model.DescribeVaultOutput;

public class Vault implements IEventRaiser<IVaultListener>
{
    public static String generateId(Region region, String vaultName)
    {
        final StringBuilder builder = new StringBuilder();
        builder.append(region.name());
        builder.append('/');
        builder.append(vaultName);
        return builder.toString();
    }

    public static Vault fromItem(Map<String, AttributeValue> item)
    {
        Vault vault = new Vault();

        int archiveCount = 0;
        if(item.containsKey("count"))
            archiveCount = Integer.parseInt(item.get("count").getN());

        vault.setArchiveCount(archiveCount);

        if(item.containsKey("created"))
        {
            Date d = DateUtil.parse(item.get("created").getS());
            vault.setCreationDate(d);
        }

        if(item.containsKey("desc"))
        {
            vault.setDescription(item.get("desc").getS());
        }

        if(item.containsKey("lastInventory"))
        {
            Date d = DateUtil.parse(item.get("lastInventory").getS());
            vault.setLastInventoryDate(d);
        }

        if(item.containsKey("localUpdate"))
        {
            Date d = DateUtil.parse(item.get("localUpdate").getS());
            vault.setLocalUpdateDate(d);
        }

        if(item.containsKey("location"))
        {
            vault.setLocation(item.get("location").getS());
        }

        vault.setName(item.get("name").getS());
        vault.setRegion(Region.valueOf(item.get("region").getS()));

        int size = 0;
        if(item.containsKey("size"))
            size = Integer.parseInt(item.get("size").getN());

        vault.setSize(size);

        return vault;
    }

    private final EventSupport<IVaultListener> mEventSupport = new EventSupport<IVaultListener>();

    private String mName;

    private String mDescription;

    private Region mRegion;

    private String mLocation;

    private long mSize;

    private Date mCreationDate;

    private Date mLastInventoryDate;

    private Date mLocalUpdateDate;

    private long mArchiveCount;

    private final List<Archive> mArchives = new ArrayList<Archive>();;

    public String getName()
    {
        return mName;
    }

    public void setName(String name)
    {
        mName = name;
    }

    public Region getRegion()
    {
        return mRegion;
    }

    public void setRegion(Region region)
    {
        mRegion = region;
    }

    public String getLocation()
    {
        return mLocation;
    }

    public void setLocation(String location)
    {
        mLocation = location;
    }

    public String getDescription()
    {
        return mDescription;
    }

    public void setDescription(String description)
    {
        mDescription = description;
    }

    public long getSize()
    {
        return mSize;
    }

    public void setSize(long size)
    {
        mSize = size;
    }

    public Date getCreationDate()
    {
        return mCreationDate;
    }

    public void setCreationDate(Date creationDate)
    {
        mCreationDate = creationDate;
    }

    public long getArchiveCount()
    {
        return mArchiveCount;
    }

    public void setArchiveCount(long archiveCount)
    {
        mArchiveCount = archiveCount;
    }

    public Date getLastInventoryDate()
    {
        return mLastInventoryDate;
    }

    public void setLastInventoryDate(Date lastInventoryDate)
    {
        mLastInventoryDate = lastInventoryDate;
    }

    public Date getLocalUpdateDate()
    {
        return mLocalUpdateDate;
    }

    public void setLocalUpdateDate(Date d)
    {
        mLocalUpdateDate = d;
    }

    public List<Archive> getArchives()
    {
        return mArchives;
    }

    public void addArchive(Archive archive)
    {
        mArchives.add(archive);

        for(IVaultListener l : mEventSupport.getListeners())
            l.archiveAdded(this, archive);
    }

    public void removeArchive(String id)
    {
        Archive a;
        Iterator<Archive> it = mArchives.iterator();
        while(it.hasNext())
        {
            a = it.next();
            if(a.getId().equalsIgnoreCase(id))
            {
                it.remove();

                for(IVaultListener l : mEventSupport.getListeners())
                    l.archiveRemoved(this, a);

                break;
            }
        }
    }

    public void removeArchive(Archive archive)
    {
        if(mArchives.remove(archive))
        {
            for(IVaultListener l : mEventSupport.getListeners())
                l.archiveRemoved(this, archive);
        }
    }

    @Override
    public void addListener(IVaultListener listener)
    {
        mEventSupport.addListener(listener);
    }

    @Override
    public void removeListener(IVaultListener listener)
    {
        mEventSupport.removeListener(listener);
    }

    @Override
    public int hashCode()
    {
        String s = mName + mRegion;
        return s.hashCode();
    }

    @Override
    public boolean equals(Object obj)
    {
        if(obj instanceof Vault)
        {
            Vault vault = (Vault)obj;
            if(mRegion.equals(vault.getRegion()) && mName.equals(vault.getName()))
                return true;
        }

        return false;
    }

    private static final SimpleDateFormat mDateFormat = new SimpleDateFormat();

    public static Vault create(DescribeVaultOutput dvo)
    {
        Vault vault = null;
        if(dvo != null)
        {
            try
            {
                vault = new Vault();
                vault.setCreationDate(mDateFormat.parse(dvo.getCreationDate()));
                vault.setLastInventoryDate(mDateFormat.parse(dvo.getLastInventoryDate()));
                vault.setArchiveCount(dvo.getNumberOfArchives());
                vault.setName(dvo.getVaultName());
                vault.setSize(dvo.getSizeInBytes());
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
        return vault;
    }
}
